home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / RCS / lex.c,v < prev    next >
Encoding:
Text File  |  1990-02-09  |  13.0 KB  |  707 lines

  1. head     1.2;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.2
  10. date     90.02.08.17.51.19;  author jhh;  state Exp;
  11. branches ;
  12. next     1.1;
  13.  
  14. 1.1
  15. date     90.02.08.15.40.18;  author jhh;  state Exp;
  16. branches ;
  17. next     ;
  18.  
  19.  
  20. desc
  21. @@
  22.  
  23.  
  24. 1.2
  25. log
  26. @Ported to sprite (patched in changes from old version of mail
  27. @
  28. text
  29. @/*
  30.  * Copyright (c) 1980 Regents of the University of California.
  31.  * All rights reserved.
  32.  *
  33.  * Redistribution and use in source and binary forms are permitted
  34.  * provided that the above copyright notice and this paragraph are
  35.  * duplicated in all such forms and that any documentation,
  36.  * advertising materials, and other materials related to such
  37.  * distribution and use acknowledge that the software was developed
  38.  * by the University of California, Berkeley.  The name of the
  39.  * University may not be used to endorse or promote products derived
  40.  * from this software without specific prior written permission.
  41.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  42.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  43.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  44.  */
  45.  
  46. #ifndef lint
  47. static char sccsid[] = "@@(#)lex.c    5.18 (Berkeley) 2/13/89";
  48. #endif /* not lint */
  49.  
  50. #include "rcv.h"
  51. #include <sys/stat.h>
  52. #include <errno.h>
  53.  
  54. /*
  55.  * Mail -- a mail program
  56.  *
  57.  * Lexical processing of commands.
  58.  */
  59.  
  60. char    *prompt = "& ";
  61.  
  62. /*
  63.  * Set up editing on the given file name.
  64.  * If the first character of name is %, we are considered to be
  65.  * editing the file, otherwise we are reading our mail which has
  66.  * signficance for mbox and so forth.
  67.  */
  68. setfile(name)
  69.     char *name;
  70. {
  71.     FILE *ibuf;
  72.     int i;
  73.     struct stat stb;
  74.     char isedit = *name != '%';
  75.     char *who = name[1] ? name + 1 : myname;
  76.     static int shudclob;
  77.     extern char tempMesg[];
  78.     extern int errno;
  79.  
  80.     if ((name = expand(name)) == NOSTR)
  81.         return -1;
  82.  
  83.     if ((ibuf = fopen(name, "r")) == NULL) {
  84.         if (!isedit && errno == ENOENT)
  85.             goto nomail;
  86.         perror(name);
  87.         return(-1);
  88.     }
  89.  
  90.     if (fstat(fileno(ibuf), &stb) < 0) {
  91.         perror("fstat");
  92.         fclose(ibuf);
  93.         return (-1);
  94.     }
  95.  
  96.     switch (stb.st_mode & S_IFMT) {
  97.     case S_IFDIR:
  98.         fclose(ibuf);
  99.         errno = EISDIR;
  100.         perror(name);
  101.         return (-1);
  102.  
  103.     case S_IFREG:
  104.         break;
  105.  
  106.     default:
  107.         fclose(ibuf);
  108.         errno = EINVAL;
  109.         perror(name);
  110.         return (-1);
  111.     }
  112.  
  113.     /*
  114.      * Looks like all will be well.  We must now relinquish our
  115.      * hold on the current set of stuff.  Must hold signals
  116.      * while we are reading the new file, else we will ruin
  117.      * the message[] data structure.
  118.      */
  119.  
  120.     holdsigs();
  121.     if (shudclob)
  122.         quit();
  123.  
  124.     /*
  125.      * Copy the messages into /tmp
  126.      * and set pointers.
  127.      */
  128.  
  129.     readonly = 0;
  130.     if ((i = open(name, 1)) < 0)
  131.         readonly++;
  132.     else
  133.         close(i);
  134.     if (shudclob) {
  135.         fclose(itf);
  136.         fclose(otf);
  137.     }
  138.     shudclob = 1;
  139.     edit = isedit;
  140.     strcpy(prevfile, mailname);
  141.     if (name != mailname)
  142.         strcpy(mailname, name);
  143.     mailsize = fsize(ibuf);
  144.     if ((otf = fopen(tempMesg, "w")) == NULL) {
  145.         perror(tempMesg);
  146.         exit(1);
  147.     }
  148.     if ((itf = fopen(tempMesg, "r")) == NULL) {
  149.         perror(tempMesg);
  150.         exit(1);
  151.     }
  152.     remove(tempMesg);
  153.     setptr(ibuf);
  154.     setmsize(msgCount);
  155.     fclose(ibuf);
  156.     relsesigs();
  157.     sawcom = 0;
  158.     if (!edit && msgCount == 0) {
  159. nomail:
  160.         fprintf(stderr, "No mail for %s\n", who);
  161.         return -1;
  162.     }
  163.     return(0);
  164. }
  165.  
  166. int    *msgvec;
  167. int    reset_on_stop;            /* do a reset() if stopped */
  168.  
  169. /*
  170.  * Interpret user commands one by one.  If standard input is not a tty,
  171.  * print no prompt.
  172.  */
  173. commands()
  174. {
  175.     int eofloop = 0;
  176.     register int n;
  177.     char linebuf[LINESIZE];
  178.     int intr(), stop(), hangup(), contin();
  179.  
  180.     if (!sourcing) {
  181.         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  182.             signal(SIGINT, intr);
  183.         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  184.             signal(SIGHUP, hangup);
  185.         signal(SIGTSTP, stop);
  186.         signal(SIGTTOU, stop);
  187.         signal(SIGTTIN, stop);
  188.     }
  189.     setexit();
  190.     for (;;) {
  191.         /*
  192.          * Print the prompt, if needed.  Clear out
  193.          * string space, and flush the output.
  194.          */
  195.         if (!sourcing && value("interactive") != NOSTR) {
  196.             reset_on_stop = 1;
  197.             printf(prompt);
  198.         }
  199.         fflush(stdout);
  200.         sreset();
  201.         /*
  202.          * Read a line of commands from the current input
  203.          * and handle end of file specially.
  204.          */
  205.         n = 0;
  206.         for (;;) {
  207.             if (readline(input, &linebuf[n], LINESIZE - n) < 0) {
  208.                 if (n == 0)
  209.                     n = -1;
  210.                 break;
  211.             }
  212.             if ((n = strlen(linebuf)) == 0)
  213.                 break;
  214.             n--;
  215.             if (linebuf[n] != '\\')
  216.                 break;
  217.             linebuf[n++] = ' ';
  218.         }
  219.         reset_on_stop = 0;
  220.         if (n < 0) {
  221.                 /* eof */
  222.             if (loading)
  223.                 break;
  224.             if (sourcing) {
  225.                 unstack();
  226.                 continue;
  227.             }
  228.             if (value("interactive") != NOSTR &&
  229.                 value("ignoreeof") != NOSTR &&
  230.                 ++eofloop < 25) {
  231.                 printf("Use \"quit\" to quit.\n");
  232.                 continue;
  233.             }
  234.             break;
  235.         }
  236.         eofloop = 0;
  237.         if (execute(linebuf, 0))
  238.             break;
  239.     }
  240. }
  241.  
  242. /*
  243.  * Execute a single command.
  244.  * Command functions return 0 for success, 1 for error, and -1
  245.  * for abort.  A 1 or -1 aborts a load or source.  A -1 aborts
  246.  * the interactive command loop.
  247.  * Contxt is non-zero if called while composing mail.
  248.  */
  249. execute(linebuf, contxt)
  250.     char linebuf[];
  251. {
  252.     char word[LINESIZE];
  253.     char *arglist[MAXARGC];
  254.     struct cmd *com;
  255.     register char *cp, *cp2;
  256.     register int c;
  257.     int muvec[2];
  258.     int e = 1;
  259.  
  260.     /*
  261.      * Strip the white space away from the beginning
  262.      * of the command, then scan out a word, which
  263.      * consists of anything except digits and white space.
  264.      *
  265.      * Handle ! escapes differently to get the correct
  266.      * lexical conventions.
  267.      */
  268.  
  269.     for (cp = linebuf; isspace(*cp); cp++)
  270.         ;
  271.     if (*cp == '!') {
  272.         if (sourcing) {
  273.             printf("Can't \"!\" while sourcing\n");
  274.             goto out;
  275.         }
  276.         shell(cp+1);
  277.         return(0);
  278.     }
  279.     cp2 = word;
  280.     while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR)
  281.         *cp2++ = *cp++;
  282.     *cp2 = '\0';
  283.  
  284.     /*
  285.      * Look up the command; if not found, bitch.
  286.      * Normally, a blank command would map to the
  287.      * first command in the table; while sourcing,
  288.      * however, we ignore blank lines to eliminate
  289.      * confusion.
  290.      */
  291.  
  292.     if (sourcing && *word == '\0')
  293.         return(0);
  294.     com = lex(word);
  295.     if (com == NONE) {
  296.         printf("Unknown command: \"%s\"\n", word);
  297.         goto out;
  298.     }
  299.  
  300.     /*
  301.      * See if we should execute the command -- if a conditional
  302.      * we always execute it, otherwise, check the state of cond.
  303.      */
  304.  
  305.     if ((com->c_argtype & F) == 0)
  306.         if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode)
  307.             return(0);
  308.  
  309.     /*
  310.      * Process the arguments to the command, depending
  311.      * on the type he expects.  Default to an error.
  312.      * If we are sourcing an interactive command, it's
  313.      * an error.
  314.      */
  315.  
  316.     if (!rcvmode && (com->c_argtype & M) == 0) {
  317.         printf("May not execute \"%s\" while sending\n",
  318.             com->c_name);
  319.         goto out;
  320.     }
  321.     if (sourcing && com->c_argtype & I) {
  322.         printf("May not execute \"%s\" while sourcing\n",
  323.             com->c_name);
  324.         goto out;
  325.     }
  326.     if (readonly && com->c_argtype & W) {
  327.         printf("May not execute \"%s\" -- message file is read only\n",
  328.            com->c_name);
  329.         goto out;
  330.     }
  331.     if (contxt && com->c_argtype & R) {
  332.         printf("Cannot recursively invoke \"%s\"\n", com->c_name);
  333.         goto out;
  334.     }
  335.     switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
  336.     case MSGLIST:
  337.         /*
  338.          * A message list defaulting to nearest forward
  339.          * legal message.
  340.          */
  341.         if (msgvec == 0) {
  342.             printf("Illegal use of \"message list\"\n");
  343.             break;
  344.         }
  345.         if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
  346.             break;
  347.         if (c  == 0) {
  348.             *msgvec = first(com->c_msgflag,
  349.                 com->c_msgmask);
  350.             msgvec[1] = NULL;
  351.         }
  352.         if (*msgvec == NULL) {
  353.             printf("No applicable messages\n");
  354.             break;
  355.         }
  356.         e = (*com->c_func)(msgvec);
  357.         break;
  358.  
  359.     case NDMLIST:
  360.         /*
  361.          * A message list with no defaults, but no error
  362.          * if none exist.
  363.          */
  364.         if (msgvec == 0) {
  365.             printf("Illegal use of \"message list\"\n");
  366.             break;
  367.         }
  368.         if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
  369.             break;
  370.         e = (*com->c_func)(msgvec);
  371.         break;
  372.  
  373.     case STRLIST:
  374.         /*
  375.          * Just the straight string, with
  376.          * leading blanks removed.
  377.          */
  378.         while (isspace(*cp))
  379.             cp++;
  380.         e = (*com->c_func)(cp);
  381.         break;
  382.  
  383.     case RAWLIST:
  384.         /*
  385.          * A vector of strings, in shell style.
  386.          */
  387.         if ((c = getrawlist(cp, arglist,
  388.                 sizeof arglist / sizeof *arglist)) < 0)
  389.             break;
  390.         if (c < com->c_minargs) {
  391.             printf("%s requires at least %d arg(s)\n",
  392.                 com->c_name, com->c_minargs);
  393.             break;
  394.         }
  395.         if (c > com->c_maxargs) {
  396.             printf("%s takes no more than %d arg(s)\n",
  397.                 com->c_name, com->c_maxargs);
  398.             break;
  399.         }
  400.         e = (*com->c_func)(arglist);
  401.         break;
  402.  
  403.     case NOLIST:
  404.         /*
  405.          * Just the constant zero, for exiting,
  406.          * eg.
  407.          */
  408.         e = (*com->c_func)(0);
  409.         break;
  410.  
  411.     default:
  412.         panic("Unknown argtype");
  413.     }
  414.  
  415. out:
  416.     /*
  417.      * Exit the current source file on
  418.      * error.
  419.      */
  420.     if (e) {
  421.         if (e < 0)
  422.             return 1;
  423.         if (loading)
  424.             return 1;
  425.         if (sourcing)
  426.             unstack();
  427.         return 0;
  428.     }
  429.     if (value("autoprint") != NOSTR && com->c_argtype & P)
  430.         if ((dot->m_flag & MDELETED) == 0) {
  431.             muvec[0] = dot - &message[0] + 1;
  432.             muvec[1] = 0;
  433.             type(muvec);
  434.         }
  435.     if (!sourcing && (com->c_argtype & T) == 0)
  436.         sawcom = 1;
  437.     return(0);
  438. }
  439.  
  440. /*
  441.  * Set the size of the message vector used to construct argument
  442.  * lists to message list functions.
  443.  */
  444.  
  445. setmsize(sz)
  446. {
  447.  
  448.     if (msgvec != 0)
  449.         cfree((char *) msgvec);
  450.     msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec);
  451. }
  452.  
  453. /*
  454.  * Find the correct command in the command table corresponding
  455.  * to the passed command "word"
  456.  */
  457.  
  458. struct cmd *
  459. lex(word)
  460.     char word[];
  461. {
  462.     register struct cmd *cp;
  463.     extern struct cmd cmdtab[];
  464.  
  465.     for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
  466.         if (isprefix(word, cp->c_name))
  467.             return(cp);
  468.     return(NONE);
  469. }
  470.  
  471. /*
  472.  * Determine if as1 is a valid prefix of as2.
  473.  * Return true if yep.
  474.  */
  475.  
  476. isprefix(as1, as2)
  477.     char *as1, *as2;
  478. {
  479.     register char *s1, *s2;
  480.  
  481.     s1 = as1;
  482.     s2 = as2;
  483.     while (*s1++ == *s2)
  484.         if (*s2++ == '\0')
  485.             return(1);
  486.     return(*--s1 == '\0');
  487. }
  488.  
  489. /*
  490.  * The following gets called on receipt of an interrupt.  This is
  491.  * to abort printout of a command, mainly.
  492.  * Dispatching here when command() is inactive crashes rcv.
  493.  * Close all open files except 0, 1, 2, and the temporary.
  494.  * Also, unstack all source files.
  495.  */
  496.  
  497. int    inithdr;            /* am printing startup headers */
  498.  
  499. #ifdef _NFILE
  500. static
  501. _fwalk(function)
  502.     register int (*function)();
  503. {
  504.     register FILE *iop;
  505.  
  506.     for (iop = _iob; iop < _iob + _NFILE; iop++)
  507.         (*function)(iop);
  508. }
  509. #else
  510. static
  511. _fwalk(function)
  512.     register int (*function)();
  513. {
  514. }
  515. #endif
  516.  
  517. static
  518. xclose(iop)
  519.     register FILE *iop;
  520. {
  521.     if (iop == stdin || iop == stdout ||
  522.         iop == stderr || iop == itf || iop == otf)
  523.         return;
  524.  
  525.     if (iop != pipef)
  526.         fclose(iop);
  527.     else {
  528.         Pclose(pipef);
  529.         pipef = NULL;
  530.     }
  531. }
  532.  
  533. /*ARGSUSED*/
  534. intr(s)
  535. {
  536.  
  537.     noreset = 0;
  538.     if (!inithdr)
  539.         sawcom++;
  540.     inithdr = 0;
  541.     while (sourcing)
  542.         unstack();
  543.  
  544.     /*
  545.      * Walk through all the open FILEs, applying xclose() to them
  546.      */
  547.     _fwalk(xclose);
  548.  
  549.     if (image >= 0) {
  550.         close(image);
  551.         image = -1;
  552.     }
  553.     fprintf(stderr, "Interrupt\n");
  554.     reset(0);
  555. }
  556.  
  557. /*
  558.  * When we wake up after ^Z, reprint the prompt.
  559.  */
  560. stop(s)
  561. {
  562.     int (*old_action)() = signal(s, SIG_DFL);
  563.  
  564.     sigsetmask(sigblock(0) & ~sigmask(s));
  565.     kill(0, s);
  566.     sigblock(sigmask(s));
  567.     signal(s, old_action);
  568.     if (reset_on_stop) {
  569.         reset_on_stop = 0;
  570.         reset(0);
  571.     }
  572. }
  573.  
  574. /*
  575.  * Branch here on hangup signal and simulate "exit".
  576.  */
  577. /*ARGSUSED*/
  578. hangup(s)
  579. {
  580.  
  581.     /* nothing to do? */
  582.     exit(1);
  583. }
  584.  
  585. /*
  586.  * Announce the presence of the current Mail version,
  587.  * give the message count, and print a header listing.
  588.  */
  589.  
  590. announce()
  591. {
  592.     int vec[2], mdot;
  593.  
  594.     mdot = newfileinfo();
  595.     vec[0] = mdot;
  596.     vec[1] = 0;
  597.     dot = &message[mdot - 1];
  598.     if (msgCount > 0 && value("noheader") == NOSTR) {
  599.         inithdr++;
  600.         headers(vec);
  601.         inithdr = 0;
  602.     }
  603. }
  604.  
  605. /*
  606.  * Announce information about the file we are editing.
  607.  * Return a likely place to set dot.
  608.  */
  609. newfileinfo()
  610. {
  611.     register struct message *mp;
  612.     register int u, n, mdot, d, s;
  613.     char fname[BUFSIZ], zname[BUFSIZ], *ename;
  614.  
  615.     for (mp = &message[0]; mp < &message[msgCount]; mp++)
  616.         if (mp->m_flag & MNEW)
  617.             break;
  618.     if (mp >= &message[msgCount])
  619.         for (mp = &message[0]; mp < &message[msgCount]; mp++)
  620.             if ((mp->m_flag & MREAD) == 0)
  621.                 break;
  622.     if (mp < &message[msgCount])
  623.         mdot = mp - &message[0] + 1;
  624.     else
  625.         mdot = 1;
  626.     s = d = 0;
  627.     for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
  628.         if (mp->m_flag & MNEW)
  629.             n++;
  630.         if ((mp->m_flag & MREAD) == 0)
  631.             u++;
  632.         if (mp->m_flag & MDELETED)
  633.             d++;
  634.         if (mp->m_flag & MSAVED)
  635.             s++;
  636.     }
  637.     ename = mailname;
  638.     if (getfold(fname) >= 0) {
  639.         strcat(fname, "/");
  640.         if (strncmp(fname, mailname, strlen(fname)) == 0) {
  641.             sprintf(zname, "+%s", mailname + strlen(fname));
  642.             ename = zname;
  643.         }
  644.     }
  645.     printf("\"%s\": ", ename);
  646.     if (msgCount == 1)
  647.         printf("1 message");
  648.     else
  649.         printf("%d messages", msgCount);
  650.     if (n > 0)
  651.         printf(" %d new", n);
  652.     if (u-n > 0)
  653.         printf(" %d unread", u);
  654.     if (d > 0)
  655.         printf(" %d deleted", d);
  656.     if (s > 0)
  657.         printf(" %d saved", s);
  658.     if (readonly)
  659.         printf(" [Read only]");
  660.     printf("\n");
  661.     return(mdot);
  662. }
  663.  
  664. /*
  665.  * Print the current version number.
  666.  */
  667.  
  668. /*ARGSUSED*/
  669. pversion(e)
  670. {
  671.     extern char *version;
  672.  
  673.     printf("Version %s\n", version);
  674.     return(0);
  675. }
  676.  
  677. /*
  678.  * Load a file of user definitions.
  679.  */
  680. load(name)
  681.     char *name;
  682. {
  683.     register FILE *in, *oldin;
  684.  
  685.     if ((in = fopen(name, "r")) == NULL)
  686.         return;
  687.     oldin = input;
  688.     input = in;
  689.     loading = 1;
  690.     sourcing = 1;
  691.     commands();
  692.     loading = 0;
  693.     sourcing = 0;
  694.     input = oldin;
  695.     fclose(in);
  696. }
  697. @
  698.  
  699.  
  700. 1.1
  701. log
  702. @Initial revision
  703. @
  704. text
  705. @d481 6
  706. @
  707.